using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Common
public partial class ARPGTestPlayerBehaviour : BasePoolElement
{
    int hp;
    public int attack;
    int meet;
    
    public int Hp { get => hp;
        set
        {
            if (value < 0) hp = 0;
            else hp = value;
            sceneMgr.mainPanel.SetHp(hp);
        }
    }


    public int Meet {
        set {
            meet = value;
            sceneMgr.mainPanel.SetMeet(meet);
        }

        get {
            return meet;
        }
    }
    private void Awake()
    {
        sceneMgr = ARPGTestSceneMgr.Instance as ARPGTestSceneMgr;
        targetMonsterList = new List<ARPGTestBoarBehaviour>();
        InitData();
        InitAnim();
        InitState();
    }

    Animator anim;
    Collider collider;
    int animAttackHash, animIdolHash, animRunHash, animDeathHash;
    ARPGTestSceneMgr sceneMgr;
    ARPGTestBoarBehaviour targetMonster;
    float attackCD = 1.5f, attackPointCD = 0.7f, attackTime;
    List<ARPGTestBoarBehaviour> targetMonsterList;
    void InitData()
    {
        Hp = 1000000000;
        Meet = 0;
        attack = 0;
        collider = GetComponentInChildren<Collider>();

    }
    void InitAnim()
    {
        anim = GetComponentInChildren<Animator>();

        animAttackHash = Animator.StringToHash("attack");
        animIdolHash = Animator.StringToHash("idol");
        animRunHash = Animator.StringToHash("run");
        animDeathHash = Animator.StringToHash("death");
    }

    public override void PoolInit()
    {
        base.PoolInit();
        state.EnterIdolState();
    }

    Vector2 moveInputDir;
    float moveSpeed = 2.5f;

    public void ScreenMove(Vector2 dir)
    {
        Vector3 screenPos = Camera.main.WorldToScreenPoint(transform.position);
        screenPos.x += dir.x;
        screenPos.y += dir.y;
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
# if UNITY_EDITOR
        if (Input.anyKey)
        {
            LookAt(worldPos);
        }
# endif
        Move(worldPos - transform.position);
    }
    public void Move(Vector3 dir)
    {
        dir.y = 0;

        dir = dir.normalized;
        transform.position += dir * moveSpeed * Time.deltaTime;

    }

    void LookAt(Vector3 targetPoint)
    {
        targetPoint.y = transform.position.y;
        transform.LookAt(targetPoint);
    }
    bool CheckMonster(float range)
    {
        return Physics.CheckSphere(transform.position, range, 1 << 31);
    }

    public void Damager(int damge)
    {
        Hp -= damge;
    }

    bool isAttack, isChecked;
    void Attack()
    {
        isAttack = true;
        isChecked = false;
        attackTime = 0;
        anim.SetTrigger(animAttackHash);
    }

    void AttackUpdate()
    {
        attackTime += Time.deltaTime;
        if (attackTime > attackCD)
        {
            isAttack = false;
        }
        if (attackTime > attackPointCD && !isChecked)
        {
            isChecked = true;
            for (int i = 0; i < targetMonsterList.Count; i++)
            {
                targetMonsterList[i].Damage(this);
            }
        }
    }

    void DeathUpdate()
    {
        if (Hp < 1 && state.State != ARPGTestPlayerState.Death)
        {
            state.EnterDeathState();
        }
    }

    void MonsterCheckUpdate()
    {
        if (isAttack) return;
        if (CheckMonster(2f))
        {
            GetMonsters(2f, 55);
            if (targetMonsterList.Count > 0)
            {
                Attack();
            }
        }
    }

    void GetMonsters(float range, float angle)
    {
        targetMonsterList.Clear();
        int c = Physics.OverlapSphereNonAlloc(transform.position, range, sceneMgr.checkMonsters, 1 << 31);
        if (c > 0)
        {
            Vector3 mo;
            for (int i = 0; i < c; i++)
            {
                mo = sceneMgr.checkMonsters[i].transform.position - transform.position;
                if (Vector3.Angle(transform.forward, mo) < angle)
                {
                    targetMonsterList.Add(sceneMgr.checkMonsters[i].GetComponent<ARPGTestBoarBehaviour>());
                }
            }
        }
    }


    ARPGTestBoarBehaviour GetNearestMonster(float range, float angle)
    {
        int c = Physics.OverlapSphereNonAlloc(transform.position, range, sceneMgr.checkMonsters, 1 << 31);
        if (c > 0)
        {
            int index = -1;
            float mindist = float.MaxValue;// Vector3.Distance(transform.position, sceneMgr.checkMonsters[index].transform.position);
            float currentdist = 0;
            Vector3 mo;
            for (int i = 0; i < c; i++)
            {
                mo = sceneMgr.checkMonsters[i].transform.position - transform.position;
                if (Vector3.Angle(transform.forward, mo) < angle)
                {
                    currentdist = Vector3.Distance(transform.position, sceneMgr.checkMonsters[i].transform.position);
                    if (currentdist < mindist)
                    {
                        mindist = currentdist;
                        index = i;
                    }
                }
            }
            if (index != -1)
            {
                return sceneMgr.checkMonsters[index].GetComponent<ARPGTestBoarBehaviour>();
            }
            return null;

        }
        return null;
    }

    ARPGTestBoarBehaviour GetNearestMonster(float range)
    {
        int c = Physics.OverlapSphereNonAlloc(transform.position, range, sceneMgr.checkMonsters, 1 << 31);
        Debug.Log($"C:{c}");
        if (c > 0)
        {
            int index = 0;
            float mindist = Vector3.Distance(transform.position, sceneMgr.checkMonsters[index].transform.position);
            float currentdist = 0;
            for (int i = 1; i < c; i++)
            {
                currentdist = Vector3.Distance(transform.position, sceneMgr.checkMonsters[i].transform.position);
                if (currentdist < mindist)
                {
                    mindist = currentdist;
                    index = i;
                }
            }
            return sceneMgr.checkMonsters[index].GetComponent<ARPGTestBoarBehaviour>();
        }
        return null;
    }
    // Start is called before the first frame update
    void Start()
    {

    }

    public ARPGTestPlayerState Stat => state.State;


    // Update is called once per frame
    private void Update()
    {
        DeathUpdate();
        state.StateUpdate();
        AttackUpdate();
    }



}

//State
public partial class ARPGTestPlayerBehaviour
{

    ARPGTestPlayerStateBehaviour state;
    void InitState()
    {
        state = new ARPGTestPlayerStateBehaviour();
        state.onAttackEnter = OnAttackEnter;
        state.onIdolEnter = OnIdolEnter;
        state.onMoveEnter = OnMoveEnter;
        state.onDeathEnter = OnDeathEnter;
        state.onAttackUpdate = OnAttackUpdate;
        state.onIdolUpdate = OnIdolUpdate;
        state.onMoveUpdate = OnMoveUpdata;

    }

    void OnAttackEnter(ARPGTestPlayerStateBehaviour state)
    {
        Debug.Log("OnAttackEnter");
        anim.SetTrigger(animAttackHash);
        attackTime = 0;
    }

    void OnAttackUpdate(ARPGTestPlayerStateBehaviour state)
    {
        if (moveInputDir != Vector2.zero)
        {
            ScreenMove(moveInputDir);
            //MonsterCheckUpdate();
        }
        attackTime += Time.deltaTime;
        if (attackTime > attackCD)
        {
            if (moveInputDir != Vector2.zero)
            {
                state.EnterMoveState();
            }
            else
            {
                state.EnterIdolState();
            }

        }
    }


    void OnIdolEnter(ARPGTestPlayerStateBehaviour state)
    {
        anim.SetTrigger(animIdolHash);
    }

    void OnIdolUpdate(ARPGTestPlayerStateBehaviour state)
    {
        if (moveInputDir != Vector2.zero)
        {
            state.EnterMoveState();
        }
        MonsterCheckUpdate();
    }

    void OnMoveEnter(ARPGTestPlayerStateBehaviour state)
    {
        anim.SetTrigger(animRunHash);
    }

    void OnMoveUpdata(ARPGTestPlayerStateBehaviour state)
    {
        if (moveInputDir != Vector2.zero)
        {
            ScreenMove(moveInputDir);
            MonsterCheckUpdate();
        }
        else
        {
            state.EnterIdolState();
        }

    }

    void OnDeathEnter(ARPGTestPlayerStateBehaviour state)
    {

        anim.SetTrigger(animDeathHash);

    }
}
//Input
public partial class ARPGTestPlayerBehaviour
{
    internal void SetInputDir(Vector2 inputDir)
    {
        moveInputDir = inputDir;
    }
}
public enum ARPGTestPlayerState
{
    Move, Death, Idol, Attack
}


